package com.itheima.a05;

import org.apache.ibatis.annotations.Mapper;
import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;

/**
 * @author: AirMan
 * @date: 2025/4/10 21:33
 * @description:
 */
public class MyMapperPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFacyory) throws BeansException {

        try {
            PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();
            Resource[] resources = patternResolver.getResources("classpath:com/itheima/a05/mapper/**/*.class");
            CachingMetadataReaderFactory reader = new CachingMetadataReaderFactory();
            AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
            for (Resource resource : resources) {
                MetadataReader metadata = reader.getMetadataReader(resource);
                ClassMetadata classMetadata = metadata.getClassMetadata();
                if (classMetadata.isInterface()
                        && metadata.getAnnotationMetadata().hasAnnotation(Mapper.class.getName())) {
                    AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
                            .genericBeanDefinition(MapperFactoryBean.class)
                            .addConstructorArgValue(classMetadata.getClassName()) // 设置 BeanFactoryBean的构造参数
                            .setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE) // 设置 BeanFactoryBean 参数的自动注入
                            .getBeanDefinition();
                    // 1. Spring 的诡异做法，根据接口生成的 BeanDefinition 仅为根据接口名生成 bean 名
                    // 所以我们需要根据接口名定义 bean 的名字
                    AbstractBeanDefinition nameMetadata = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition();
                    String name = generator.generateBeanName(nameMetadata, beanFacyory);
                    beanFacyory.registerBeanDefinition(name, beanDefinition);
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}
